<?php
/**
 * 操作ini类
 * $fileaddr:ini路径，$section:只选择某个节点操作，默认操作整个ini，$allowModifications:是否允许对ini进行写操作
 * @author levsion@163.com 2010
 *
 */
class ParseConfigIni{
	public $fileaddr;
	protected $section;
	public $allowModifications;
	protected $_data = array();
	
	function __construct($fileaddr, $section = null,$allowModifications = false){
		if(is_string($fileaddr) && (empty($fileaddr) || !file_exists($fileaddr)) ){
			throw new Exception("not found the file in ".$fileaddr);
			exit();
		}
		$this->fileaddr = $fileaddr;
		$this->section = $section;
		$this->allowModifications = (boolean)$allowModifications;
		$iniArray = is_string($fileaddr) ? parse_ini_file($fileaddr,true) : $fileaddr;
		$preProcessedArray = array();
		foreach ($iniArray as $key=>$data) {//作用：给继承节点增加';extends'=>'父节点',加分号避免与extends关键字冲突
			$bits = explode(':', $key);
            $thisSection = trim($bits[0]);
            switch (count($bits)) {
                case 1:
                    $preProcessedArray[$thisSection] = $data;
                    break;

                case 2:
                    $extendedSection = trim($bits[1]);
                    $preProcessedArray[$thisSection] = array_merge(array(';extends'=>$extendedSection), $data);
                    break;

                default:
                    throw new Exception("Section '$thisSection' may not extend multiple sections in $fileaddr");
            }
		}
		$dataArray = array();
		if($section === null){
			$dataArray = $preProcessedArray;
		}else if(is_array($section)){
			foreach ($section as $sectionName){
				if (!isset($preProcessedArray[$sectionName])){
                    throw new Exception("Section '$sectionName' cannot be found in $fileaddr");
                }
                if(isset($preProcessedArray[$sectionName][';extends'])){
                	$_extends = $preProcessedArray[$sectionName][';extends'];
                	$dataArray[$sectionName] = $preProcessedArray[$sectionName] + $preProcessedArray[$_extends];
                }else{
                	$dataArray[$sectionName] = $preProcessedArray[$sectionName];
                }
			}
		}else{
			if (!isset($preProcessedArray[$section])){
            	throw new Exception("Section '$section' cannot be found in $fileaddr");
			}
			if(isset($preProcessedArray[$section][';extends'])){
            	$_extends = $preProcessedArray[$section][';extends'];
            	$dataArray[$section] = $preProcessedArray[$section] + $preProcessedArray[$_extends];
            }else{
            	$dataArray[$section] = $preProcessedArray[$section];
            }
		}
		foreach ($dataArray as $key => $value) {
            if (is_array($value)){
                $this->_data[$key] = new self($value,$this->section, $this->allowModifications);
            }else{
                $this->_data[$key] = $value;
            }
        }
		
	}
	
	/**
	 * 通过魔术方法访问属性，并返回该属性值
	 *
	 * @param string $name
	 * @return mixd
	 */
	public function __get($name){
        return $this->get($name);
    }
    /**
     * 在$allowModifications开启状态下允许设置，否则抛出异常
     *
     * @param  string $name
     * @param  mixed  $value
     * @throws Exception
     * @return void
     */
    public function __set($name, $value){
        if ($this->allowModifications) {
            if (is_array($value)) {
                $this->_data[$name] = new self($value, true);
            } else {
                $this->_data[$name] = $value;
            }
            $this->set();
        } else {
            throw new Exception($this->fileaddr.' is read only');
        }
    }
    
    function get($name){
    	return array_key_exists($name, $this->_data) ? $this->_data[$name] : null;
    }
    
    function set(){
    	
    }
    
    /**
     * Return an associative array of the stored data.
     *
     * @return array
     */
    public function toArray()
    {
        $array = array();
        foreach ($this->_data as $key => $value) {
            if ($value instanceof ParseConfigIni) {
                $array[$key] = $value->toArray();
            } else {
                $array[$key] = $value;
            }
        }
        return $array;
    }
    
    /**
     * Support isset() overloading on PHP 5.1
     *
     * @param string $name
     * @return boolean
     */
    public function __isset($name)
    {
        return isset($this->_data[$name]);
    }
    
    /**
     * Prevent any more modifications being made to this instance. Useful
     * after merge() has been used to merge multiple Config objects
     * into one object which should then not be modified again.
     *
     */
    public function setReadOnly(){
        $this->allowModifications = false;
    }
    
    /**
     * Returns if this Config object is read only or not.
     *
     * @return boolean
     */
    public function readOnly(){
        return !$this->allowModifications;
    }
}

?>